﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.ComponentModel;
using System.Windows.Threading;

namespace GameLogic.Controls
{
    [TemplatePart(Name = C_TimerTextName, Type = typeof(TextBlock))]
    public class TimerControl : Control
    {
        const string C_TimerTextName = "_timerText";
        TextBlock timerText;
        DateTime lastTick;
        DispatcherTimer timer;
        bool isPaused = false;

        public event EventHandler<TimerStatusEventArgs> StatusChanged;
        public event EventHandler TimerDefeat;

        #region Dependency Properties

        [Category("Timer")]
        public TimeSpan StartValue
        {
            get { return (TimeSpan)GetValue(StartValueProperty); }
            set { SetValue(StartValueProperty, value); }
        }

        public static readonly DependencyProperty StartValueProperty =
            DependencyProperty.Register(
                "StartValue",
                typeof(TimeSpan),
                typeof(TimerControl),
                new PropertyMetadata(new TimeSpan(0, 0, 30)));

        [Category("Timer")]
        public TimeSpan DefeatValue
        {
            get { return (TimeSpan)GetValue(DefeatValueProperty); }
            set { SetValue(DefeatValueProperty, value); }
        }
        public static readonly DependencyProperty DefeatValueProperty =
            DependencyProperty.Register(
                "DefeatValue",
                typeof(TimeSpan),
                typeof(TimerControl),
                new PropertyMetadata(new TimeSpan(0, 0, 0)));

        [Category("Timer")]
        public int TimerStepsInMilliseconds
        {
            get { return (int)GetValue(TimerStepsInMillisecondsProperty); }
            set { SetValue(TimerStepsInMillisecondsProperty, value); }
        }
        public static readonly DependencyProperty TimerStepsInMillisecondsProperty =
            DependencyProperty.Register(
                "TimerStepsInMilliseconds",
                typeof(int),
                typeof(TimerControl),
                new PropertyMetadata(1000));

        [Category("Timer")]
        public bool IsCountdown
        {
            get { return (bool)GetValue(IsCountdownProperty); }
            set { SetValue(IsCountdownProperty, value); }
        }

        public static readonly DependencyProperty IsCountdownProperty =
            DependencyProperty.Register(
                "TimerAsCountdown", 
                typeof(bool), 
                typeof(TimerControl), 
                new PropertyMetadata(true, null));

        [Category("Timer")]
        public bool IsDefeatCondition
        {
            get { return (bool)GetValue(IsDefeatConditionProperty); }
            set { SetValue(IsDefeatConditionProperty, value); }
        }

        public static readonly DependencyProperty IsDefeatConditionProperty =
            DependencyProperty.Register(
                "IsDefeatCondition", 
                typeof(bool), 
                typeof(TimerControl),
                new PropertyMetadata(true, null));

        #endregion

        public TimeSpan CurrentValue
        {
            get;
            private set;
        }

         // Constructor
        public TimerControl()
        {
            this.DefaultStyleKey = typeof(TimerControl);
            timer = new DispatcherTimer();

            timer.Tick += OnTimerTick;
        }

        //~TimerControl()
        //{
        //    timer.Stop();
        //    timer.Tick -= OnTimerTick;       
        //}

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            timerText = GetTemplateChild(C_TimerTextName) as TextBlock;
            this.UpdateDisplay();
        }

        public void Start()
        {
            timer.Interval = new TimeSpan(0, 0, 0, 0, TimerStepsInMilliseconds);
            timer.Start();

            if (isPaused)
            {
                OnStatusChanged(TimerStatus.Resumed);
            }
            else
            {
                this.CurrentValue = this.StartValue;
                OnStatusChanged(TimerStatus.Started);
            }

            this.SaveLastTick();
            isPaused = false;
            this.UpdateDisplay();
        }

        public void Add(TimeSpan timeSpan)
        {
            this.CurrentValue = this.CurrentValue.Add(timeSpan);
            this.UpdateDisplay();
            OnStatusChanged(TimerStatus.TimeChanged);
            CheckTime();
        }

        public void Pause()
        {
            timer.Stop();
            isPaused = true;
            OnStatusChanged(TimerStatus.Paused);
        }

        public void Stop()
        {
            timer.Stop();
            OnStatusChanged(TimerStatus.Stopped);
            isPaused = false;
        }

        private void OnTimerTick(object sender, EventArgs e)
        {
            TimeSpan diff = DateTime.Now - this.lastTick;

            if (this.IsCountdown)
            {
                this.CurrentValue = this.CurrentValue.Add(-diff);
            }
            else
            {
                this.CurrentValue = this.CurrentValue.Add(diff);
            }

            this.CheckTime();
            this.UpdateDisplay();
            this.SaveLastTick();
        }

       
        private void OnStatusChanged(TimerStatus timerStatus)
        {
            if (StatusChanged != null)
            {
                TimerStatusEventArgs args = new TimerStatusEventArgs();
                args.TimerStatus = timerStatus;
                StatusChanged(this, args);
            }
        }

        private void CheckTime()
        {
            if (this.IsDefeatCondition &&  this.IsCountdown && this.CurrentValue <= this.DefeatValue)
            {
                this.OnTimerDefeat();
            }
            else if (this.IsDefeatCondition && !this.IsCountdown && this.CurrentValue >= this.DefeatValue)
            {
                this.OnTimerDefeat();
            }
        }
      
        private void OnTimerDefeat()
        {
            this.Stop();
            this.OnStatusChanged(TimerStatus.DefeatValueReached);

            if (TimerDefeat != null)
            {
                TimerDefeat(this, EventArgs.Empty);
            }
        }

        private void SaveLastTick()
        {
            lastTick = DateTime.Now;
        }

        private void UpdateDisplay()
        {
            // only update if visible/existing

            // TODO: Visible????
            if (timerText != null)
            {
                // TODO: Format time and check if update is necessary
                this.timerText.Text = string.Format(
                    "{0:00}:{1:00}:{2:00}",
                    this.CurrentValue.Hours,
                    this.CurrentValue.Minutes,
                    this.CurrentValue.Seconds);

                UpdateLayout();
            }
        }
    }
}
